package com.example.mcu.serial;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.Serializable;
import java.nio.ByteBuffer;

import com.example.mcu_up.serial.BadPackageException;

import android.util.Log;

public class Pack implements Serializable {

	private byte header;
	private byte type;// 类型
	private int len = 0;// 长度
	private byte[] data;// 数据
	private byte check;

	public byte getHeader() {
		return header;
	}

	public void setHeader(byte header) {
		this.header = header;
	}

	public byte getCheck() {
		return check;
	}

	public void setCheck(byte check) {
		this.check = check;
	}

	public byte getType() {
		return type;
	}

	public void setType(byte type) {
		this.type = type;
	}

	public int getLen() {
		return len;
	}

	public void setLen(int len) {
		this.len = len;
	}

	public byte[] getData() {
		return data;
	}

	public void setData(byte[] data) {
		this.data = data;
	}

	// byte 数组与 int 的相互转换
	public static int byteArrayToInt(byte[] b) {
		return b[3] & 0xFF | (b[2] & 0xFF) << 8 | (b[1] & 0xFF) << 16
				| (b[0] & 0xFF) << 24;
	}

	public static byte[] intToByteArray(int a) {
		return new byte[] { (byte) ((a >> 24) & 0xFF),
				(byte) ((a >> 16) & 0xFF), (byte) ((a >> 8) & 0xFF),
				(byte) (a & 0xFF) };
	}

	/**
	 * 将int数值转换为占四个字节的byte数组，本方法适用于(高位在前，低位在后)的顺序。 和bytesToInt2（）配套使用
	 */
	public static byte[] intToBytes2(int value) {
		byte[] src = new byte[2];

		src[0] = (byte) ((value >> 8) & 0xFF);
		src[1] = (byte) (value & 0xFF);
		return src;
	}

	/**
	 * byte数组中取int数值，本方法适用于(高位在前，低位在后)的顺序。和intToBytes2（）配套使用
	 */

	public static int bytesToInt2(byte[] src, int offset) {
		int value;
		value = (int) ((src[offset] & 0xFF) << 8) | (src[offset + 1] & 0xFF);
		return value;
	}

	/**
	 * 将32位的int值放到4字节的里
	 * 
	 * @param num
	 * @return
	 */
	public static byte[] int2byteArray(int num) {
		byte[] result = new byte[4];
		result[0] = (byte) (num >>> 24);// 取最高8位放到0下标
		result[1] = (byte) (num >>> 16);// 取次高8为放到1下标
		result[2] = (byte) (num >>> 8); // 取次低8位放到2下标
		result[3] = (byte) (num); // 取最低8位放到3下标
		return result;
	}

	/**
	 * 将4字节的byte数组转成一个int值
	 * 
	 * @param b
	 * @return
	 */
	public static int byteArray2int(byte[] b) {
		byte[] a = new byte[4];
		int i = a.length - 1, j = b.length - 1;
		for (; i >= 0; i--, j--) {// 从b的尾部(即int值的低位)开始copy数据
			if (j >= 0)
				a[i] = b[j];
			else
				a[i] = 0;// 如果b.length不足4,则将高位补0
		}
		int v0 = (a[0] & 0xff) << 24;// &0xff将byte值无差异转成int,避免Java自动类型提升后,会保留高位的符号位
		int v1 = (a[1] & 0xff) << 16;
		int v2 = (a[2] & 0xff) << 8;
		int v3 = (a[3] & 0xff);
		return v0 + v1 + v2 + v3;
	}

	/*
	 * byte为一位数的时候用
	 */
	public static int readOne(byte[] b) {
		int a = -1;
		DataInputStream dis = new DataInputStream(new ByteArrayInputStream(b));
		try {
			a = dis.readByte();
		} catch (IOException e) {
			// TODO 自动生成的 catch 块
			e.printStackTrace();
		}
		return a;
	}

	/*
	 * 1,2时候用
	 */
	public static int[] readOneTwo(byte[] b) {
		int[] a = new int[2];
		DataInputStream dis = new DataInputStream(new ByteArrayInputStream(b));
		try {
			a[0] = dis.readByte();
			a[1] = dis.readShort();
		} catch (IOException e) {
			// TODO 自动生成的 catch 块
			e.printStackTrace();
		}
		return a;
	}

	/*
	 * 2,2时候用
	 */
	public static int[] readTwoTwo(byte[] b) {
		int[] a = new int[2];
		DataInputStream dis = new DataInputStream(new ByteArrayInputStream(b));
		try {
			a[0] = dis.readShort();
			a[1] = dis.readShort();
		} catch (IOException e) {
			// TODO 自动生成的 catch 块
			e.printStackTrace();
		}
		return a;
	}

	/*
	 * 1,2,2时候用
	 */
	public static int[] readOneTwoTwo(byte[] b) {
		int[] a = new int[3];
		DataInputStream dis = new DataInputStream(new ByteArrayInputStream(b));
		try {
			a[0] = dis.readByte();
			a[1] = dis.readShort();
			a[2] = dis.readShort();
		} catch (IOException e) {
			// TODO 自动生成的 catch 块
			e.printStackTrace();
		}
		return a;
	}

	/*
	 * 应答码时候用
	 */
	public static String answer(byte[] b) {
		String a = null;
		DataInputStream dis = new DataInputStream(new ByteArrayInputStream(b));
		try {
			a = dis.readByte() == 1 ? "OK" : "Error";
		} catch (IOException e) {
			// TODO 自动生成的 catch 块
			e.printStackTrace();
		}
		return a;
	}

	/*
	 * 接收包，如果type类型 为0x00就是应答包，如果不是就是正常 的包
	 */

	public Pack getPack(InputStream is) throws IOException, BadPackageException {

		Pack p = new Pack();
		ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
		DataInputStream dis = new DataInputStream(is);
		header = dis.readByte();
		if (header != (byte) 0x5A) {
			throw new BadPackageException("wrong synchronize header." + header);
		}

		type = dis.readByte();
		/*
		 * if (type == (byte) 0x00) { p.setType(type); data[0] = dis.readByte();
		 * p.setData(data); check = dis.readByte(); p.setCheck(check); } else
		 */{
			p.setType(type);
			len = dis.readShort();
			p.setLen(len);
			int remaining = len;
			byte[] buf = new byte[1024];
			while (remaining > 0) {
				int c = dis.read(buf, 0, remaining > 1024 ? 1024 : remaining);
				outputStream.write(buf, 0, c);
				remaining -= c;
			}
			p.setData(outputStream.toByteArray());
		}
		return p;
	}

	/*
	 * 打包，如果type为0x00就是应答包,如果不是就是正常 的包
	 */
	public byte[] tobytes() {
		len = 0;
		header = (byte) 0x5A;
		ByteBuffer b = null;

		if (type == (byte) 0x00) {
			b = ByteBuffer.allocate(3);
			b.put(header);
			b.put(type);
			b.put(data);
		} else {

			if (type == (byte) 0x09) {
				len = getData().length + 1;
			} else {
				if (getData() != null && getData().length > 0) {
					len = getData().length;
				} else {
					len = 0;
				}
			}

			b = ByteBuffer.allocate(len + 4);

			b.put(header);// 头
			b.put(type);// 类型

			b.put(intToBytes2(len));// 长度

			if (getData() != null && getData().length > 0) {
				b.put(getData());
			}

			Log.i("testindex", String.valueOf(len));
			if (type == (byte) 0x09) {
				check = CRC8.calcCrc8(b.array());
				Log.i("Check", String.valueOf(check));
				Log.i("Check", String.valueOf(b.array().length));
				b.put(check);// 校验码
			}
		}

		return b.array();

	}

	/**
	 * DOC 从文件里读取数据.
	 * 
	 * @throws FileNotFoundException
	 * @throws IOException
	 */

	private static byte[] readEQFile(String filepath) {
		String str = "";// 用来将每次读取到的字符拼接，当然使用StringBuffer类更好
		try {
			File file = new File(filepath);// 指定要读取的文件
			FileReader reader = new FileReader(file);// 获取该文件的输入流
			char[] bb = new char[2];// 用来保存每次读取到的字符
			int n;// 每次读取到的字符长度
			while ((n = reader.read(bb)) != -1) {
				str = new String(bb, 0, n) + "'" + str;
			}
			reader.close();// 关闭输入流，释放连接
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		String[] strs = getArray(str.split("\'"));
		byte[] mybytes = new byte[strs.length];
		for (int i = 0; i < strs.length; i++) {
			mybytes[i] = (byte) Integer.parseInt(strs[i]);
		}
		return mybytes;
	}

	/**
	 * 处理数组反转
	 * 
	 * @param array
	 * @return
	 */
	public static String[] getArray(String[] array) {
		String t[] = new String[array.length]; // 开辟一个新的数组
		int count = t.length - 1;
		for (int x = 0; x < t.length; x++) {
			t[count] = array[x]; // 数组反转
			count--;
		}
		return t;
	}

	public static final byte[] input2byte(InputStream inStream)
			throws IOException {
		ByteArrayOutputStream swapStream = new ByteArrayOutputStream();
		byte[] buff = new byte[100];
		int rc = 0;
		while ((rc = inStream.read(buff, 0, 100)) > 0) {
			swapStream.write(buff, 0, rc);
		}
		byte[] in2b = swapStream.toByteArray();
		return in2b;
	}

	public static void main(String[] args) {

		Pack p = new Pack();
		byte[] bb = new byte[200];
		for (int i = 0; i < 200; i++) {
			bb[i] = (byte) i;
		}

		p.setType((byte) 0x01);
		p.setData(bb);

		System.out.println(p);

		byte[] by = p.tobytes();
		System.out.println(by.length);

		for (byte pk : by)
			System.out.print(" " + pk);

		System.out.println();
		byte[] bx = new byte[2];
		bx[0] = by[1];
		bx[1] = by[2];
		System.out.println(bytesToInt3(bx, 0));

	}

	public static int bytesToInt3(byte[] src, int offset) {
		int value;
		value = (int) ((src[offset] & 0xFF) << 8) | (src[offset + 1] & 0xFF);

		if (((src[offset] & 0xFF) << 8) >= 1 && (src[offset + 1] & 0xFF) < 0) {

			value = (int) ((src[offset] & 0xFF) << 8)
					| (src[offset + 1] & 0xFF) + 256;
		}

		return value;
	}

}

class CRC8 {
	static byte[] crc8_tab = { (byte) 0, (byte) 94, (byte) 188, (byte) 226,
			(byte) 97, (byte) 63, (byte) 221, (byte) 131, (byte) 194,
			(byte) 156, (byte) 126, (byte) 32, (byte) 163, (byte) 253,
			(byte) 31, (byte) 65, (byte) 157, (byte) 195, (byte) 33,
			(byte) 127, (byte) 252, (byte) 162, (byte) 64, (byte) 30,
			(byte) 95, (byte) 1, (byte) 227, (byte) 189, (byte) 62, (byte) 96,
			(byte) 130, (byte) 220, (byte) 35, (byte) 125, (byte) 159,
			(byte) 193, (byte) 66, (byte) 28, (byte) 254, (byte) 160,
			(byte) 225, (byte) 191, (byte) 93, (byte) 3, (byte) 128,
			(byte) 222, (byte) 60, (byte) 98, (byte) 190, (byte) 224, (byte) 2,
			(byte) 92, (byte) 223, (byte) 129, (byte) 99, (byte) 61,
			(byte) 124, (byte) 34, (byte) 192, (byte) 158, (byte) 29,
			(byte) 67, (byte) 161, (byte) 255, (byte) 70, (byte) 24,
			(byte) 250, (byte) 164, (byte) 39, (byte) 121, (byte) 155,
			(byte) 197, (byte) 132, (byte) 218, (byte) 56, (byte) 102,
			(byte) 229, (byte) 187, (byte) 89, (byte) 7, (byte) 219,
			(byte) 133, (byte) 103, (byte) 57, (byte) 186, (byte) 228,
			(byte) 6, (byte) 88, (byte) 25, (byte) 71, (byte) 165, (byte) 251,
			(byte) 120, (byte) 38, (byte) 196, (byte) 154, (byte) 101,
			(byte) 59, (byte) 217, (byte) 135, (byte) 4, (byte) 90, (byte) 184,
			(byte) 230, (byte) 167, (byte) 249, (byte) 27, (byte) 69,
			(byte) 198, (byte) 152, (byte) 122, (byte) 36, (byte) 248,
			(byte) 166, (byte) 68, (byte) 26, (byte) 153, (byte) 199,
			(byte) 37, (byte) 123, (byte) 58, (byte) 100, (byte) 134,
			(byte) 216, (byte) 91, (byte) 5, (byte) 231, (byte) 185,
			(byte) 140, (byte) 210, (byte) 48, (byte) 110, (byte) 237,
			(byte) 179, (byte) 81, (byte) 15, (byte) 78, (byte) 16, (byte) 242,
			(byte) 172, (byte) 47, (byte) 113, (byte) 147, (byte) 205,
			(byte) 17, (byte) 79, (byte) 173, (byte) 243, (byte) 112,
			(byte) 46, (byte) 204, (byte) 146, (byte) 211, (byte) 141,
			(byte) 111, (byte) 49, (byte) 178, (byte) 236, (byte) 14,
			(byte) 80, (byte) 175, (byte) 241, (byte) 19, (byte) 77,
			(byte) 206, (byte) 144, (byte) 114, (byte) 44, (byte) 109,
			(byte) 51, (byte) 209, (byte) 143, (byte) 12, (byte) 82,
			(byte) 176, (byte) 238, (byte) 50, (byte) 108, (byte) 142,
			(byte) 208, (byte) 83, (byte) 13, (byte) 239, (byte) 177,
			(byte) 240, (byte) 174, (byte) 76, (byte) 18, (byte) 145,
			(byte) 207, (byte) 45, (byte) 115, (byte) 202, (byte) 148,
			(byte) 118, (byte) 40, (byte) 171, (byte) 245, (byte) 23,
			(byte) 73, (byte) 8, (byte) 86, (byte) 180, (byte) 234, (byte) 105,
			(byte) 55, (byte) 213, (byte) 139, (byte) 87, (byte) 9, (byte) 235,
			(byte) 181, (byte) 54, (byte) 104, (byte) 138, (byte) 212,
			(byte) 149, (byte) 203, (byte) 41, (byte) 119, (byte) 244,
			(byte) 170, (byte) 72, (byte) 22, (byte) 233, (byte) 183,
			(byte) 85, (byte) 11, (byte) 136, (byte) 214, (byte) 52,
			(byte) 106, (byte) 43, (byte) 117, (byte) 151, (byte) 201,
			(byte) 74, (byte) 20, (byte) 246, (byte) 168, (byte) 116,
			(byte) 42, (byte) 200, (byte) 150, (byte) 21, (byte) 75,
			(byte) 169, (byte) 247, (byte) 182, (byte) 232, (byte) 10,
			(byte) 84, (byte) 215, (byte) 137, (byte) 107, 53 };

	/**
	 * 计算数组的CRC8校验值
	 * 
	 * @param data
	 *            需要计算的数组
	 * @return CRC8校验值
	 */
	public static byte calcCrc8(byte[] data) {
		return calcCrc8(data, 0, data.length, (byte) 0);
	}

	/**
	 * 计算CRC8校验值
	 * 
	 * @param data
	 *            数据
	 * @param offset
	 *            起始位置
	 * @param len
	 *            长度
	 * @return 校验值
	 */
	public static byte calcCrc8(byte[] data, int offset, int len) {
		return calcCrc8(data, offset, len, (byte) 0);
	}

	/**
	 * 计算CRC8校验值
	 * 
	 * @param data
	 *            数据
	 * @param offset
	 *            起始位置
	 * @param len
	 *            长度
	 * @param preval
	 *            之前的校验值
	 * @return 校验值
	 */
	public static byte calcCrc8(byte[] data, int offset, int len, byte preval) {
		byte ret = preval;
		for (int i = offset; i < (offset + len); ++i) {
			ret = crc8_tab[(0x00ff & (ret ^ data[i]))];
		}
		return ret;
	}

	/*
	 * 校验是否成功
	 */

	public static boolean check(byte b) {
		for (byte bb : crc8_tab) {
			if (bb == b)
				return true;
		}
		return false;
	}
}